%skeleton "lalr1.cc"
%require "2.4.1"
%defines
%define parser_class_name "XMLParser"

%code requires {

using namespace std;
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <stack>
#include "commun.h"
#include "XMLParser.hh"
#include "StructureXml.h"

class XMLParserDriver;


}

%parse-param { XMLParserDriver& driver }
%lex-param   { XMLParserDriver& driver }

%locations
%initial-action
{
  // Initialize the initial location.
  @$.begin.filename = @$.end.filename = &driver.file;
};


%union {
   char * s;
   ElementName * en;  /* le nom d'un element avec son namespace */
   StructureXml* doc;
   ElementXml * el;
   list<AttributXml> * attrs;
   list<ElementXml> * elems;
   AttributXml * attr;
}

%code {
  #include "XMLParserDriver.h"
  #include "yydecl_xml.h"

}

%token TERMINATE 0
%token EQ SLASH CLOSE END CLOSESPECIAL DOCTYPE
%token <s> ENCODING VALUE DATA COMMENT NAME NSNAME
%token <en> NSSTART START STARTSPECIAL
%type <en> start
%type <s> declaration
%type <doc> document
%type <el> element
%type <attrs> attrs
%type <attr> single_attr
%type <elems> content declarations close_content_and_end empty_or_content
%%

document
 : declarations element misc_seq_opt {
    $$ = new StructureXml(*$2);
    driver.structure = $$;
  }
 ;
misc_seq_opt
 : misc_seq_opt misc
 | /*empty*/
 ;
misc
 : COMMENT		
 ;

declarations
 : declarations declaration
{
  /*$$ = $1;
  $$->push_back((ElementXml) $2);*/
}
 | /* empty */
{
  $$ = new list<ElementXml>;
}
 ;
 
declaration
 : DOCTYPE NAME NAME VALUE CLOSE {
      $$ = $4;
      driver.dtdFileName = string($4);
    }
 ;

element
 : start
   attrs
   empty_or_content
{
  string nom;
  if ($1->first != "") {
    nom = $1->first + ":" + $1->second;
  } else {
    nom = $1->second;
  }
  ElementXml * elem = new ElementXml(nom);
  elem->SetAttributeList(*$2);
  if ($3 != 0) {
    for (list<ElementXml>::const_iterator it = $3->begin(); it != $3->end(); it++) {
      elem->AddChild(*it);
    }
  }
  $$ = elem;  
}
 ;
start
 : START { $$ = $1;}
 | NSSTART { $$ = $1; }
 ;
empty_or_content
 : SLASH CLOSE { $$ = 0; }
 | 
   close_content_and_end 
   name_or_nsname_opt CLOSE
{
  $$ = $1;
}
 ;

attrs
 : attrs
   single_attr
{
  $$ = $1;
  $$->push_back(*$2);
}
 | { $$ = new list<AttributXml>; }
 ;

single_attr
 : NAME EQ VALUE { $$ = new AttributXml($1,$3); }
;

name_or_nsname_opt 
 : NAME     
 | NSNAME  
 | /* empty */
 ;
close_content_and_end
 : CLOSE
   content 
   END
{
  $$ = $2;
}
 ;
content 
 : content DATA	{ $$ = $1; $$->push_back(ElementXml("", string($2))); }
 | content misc        
 | content element {$$ = $1; $$->push_back(*$2); }
 | /*empty*/ { $$ = new list<ElementXml>; }
 ;
%%

